//========================================================================
// OpenGL triangle example
// Copyright (c) Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would
//    be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
//    be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
//    distribution.
//
//========================================================================
//! [code]

#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>

#include "linmath.h"

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>

typedef struct Vertex
{
    vec2 pos;
    vec3 col;
} Vertex;

float scale = 0.2f;
vec2 pos1 = {0.0f,0.f};
int w=28;
int h=28;
//static const Vertex vertices[24] =
/*
Vertex vertices[2*2*6] =
{
    // top right
    { {   0.f,  0.f}, { 1.f, 0.f, 0.f } },
    { {  0.5f, 0.f }, { 1.f, 0.f, 0.f } },
    { {  0.5f, 0.5f}, { 1.f, 0.f, 0.f } },

    { {  0.f,  0.f  }, { 1.f, 0.f, 0.f } },
    { {  0.5f, 0.5f }, { 1.f, 0.f, 0.f } },
    { {  0.f,  0.5f }, { 1.f, 0.f, 0.f } },

    // top left
    { {  0.f, 0.f  }, { 0.f ,1.f, 0.f } },
    { {  0.f, 0.5f }, { 0.f, 1.f, 0.f } },
    { {  -0.5f,0.5f}, { 0.f, 1.f, 0.f } },

    { {  0.f,  0.f }, { 0.f, 1.f, 0.f } },
    { {  -0.5f,0.5f}, { 0.f, 1.f, 0.f } },
    { {  -0.5f,0.f }, { 0.f, 1.f, 0.f } },

    // bottom left
    { {  0.f,  0.f }, { 1.f, 1.f, 0.f } },
    { {  -0.5f,0.f }, { 1.f, 1.f, 0.f } },
    { {  -0.5f,-0.5f}, { 1.f, 1.f, 0.f } },

    { {  0.f,  0.f},   { 1.f, 1.f, 0.f } },
    { {  -0.5f,-0.5f}, { 1.f, 1.f, 0.f } },
    { {  0.f,-0.5f},    { 1.f, 1.f, 0.f } },

    // bottom right
    { {  0.f,  0.f},  { 1.f, 0.f, 1.f } },
    { {  0.f,-0.5f},   { 1.f, 0.f, 1.f } },
    { {  0.5f, -0.5f},{ 1.f, 0.f, 1.f } },

    { {  0.f,  0.f},  { 1.f, 0.f, 1.f } },
    { {  0.5f, -0.5f}, { 1.f, 0.f, 1.f } },
    { {  0.5f, 0.f },  { 1.f, 0.f, 1.f } },

};
*/
Vertex vertices[28*28*6]={};
static const char* vertex_shader_text =
"#version 330\n"
"uniform mat4 MVP;\n"
"in vec3 vCol;\n"
"in vec2 vPos;\n"
"out vec3 color;\n"
"void main()\n"
"{\n"
"    gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
"    color = vCol;\n"
"}\n";

static const char* fragment_shader_text =
"#version 330\n"
"in vec3 color;\n"
"out vec4 fragment;\n"
"void main()\n"
"{\n"
"    fragment = vec4(color, 1.0);\n"
"}\n";

static void error_callback(int error, const char* description)
{
    fprintf(stderr, "Error: %s\n", description);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GLFW_TRUE);
}

int main(void)
{
    glfwSetErrorCallback(error_callback);

    if (!glfwInit())
        exit(EXIT_FAILURE);

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(640, 640, "OpenGL Triangle", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwSetKeyCallback(window, key_callback);

    glfwMakeContextCurrent(window);
    gladLoadGL(glfwGetProcAddress);
    glfwSwapInterval(1);

    // NOTE: OpenGL error checks have been omitted for brevity

    // write a pic
	int  img[w*h];
	for(int i=0;i<w*h;i++){
	    img[i]=1;
	}
	// read a pic from file
	FILE * fp = fopen("/Users/zhaomingming/Downloads/img_6.txt","rb");
	if(fp == NULL){printf("file open failed\n");}
	fseek(fp,0,SEEK_END);
	int file_size = ftell(fp);
	printf("float_size = %d\n",sizeof(float));
	int float_number = file_size / sizeof(float);
	printf("float_number = %d\n",float_number);
	float model[float_number];
	fseek(fp,0,SEEK_SET);
	fread(model,sizeof(float),float_number,fp);
	fclose(fp);

	float col_tmp[3]={0.f,0.f,0.f};
	for(int i=0;i<w;i++){
	    for(int j=0;j<h;j++){
		    if(model[i+j*w]>0.0f){
		        col_tmp[0]=1.f;
				col_tmp[2]=0.f;
			}else{
			    col_tmp[0]=0.f;
				col_tmp[2]=1.f;
			}
			float left = ((float)i-(float)w/2.0)/(float)w;
			float right = left+1.0/(float)w;
			float top = (-(float)j+(float)h/2.0)/(float)h;
			float bottom =top  - 1.0/(float)h;
			int k=0;
			//printf("%d,left=%f,top=%f\n",i*w*6+j*6+k,left,top);
		    k=0;vertices[i*w*6+j*6+k].pos[0]=left;vertices[i*w*6+j*6+k].pos[1]=top;
		    k=1;vertices[i*w*6+j*6+k].pos[0]=right;vertices[i*w*6+j*6+k].pos[1]=top;
		    k=2;vertices[i*w*6+j*6+k].pos[0]=left;vertices[i*w*6+j*6+k].pos[1]=bottom;
		    k=3;vertices[i*w*6+j*6+k].pos[0]=left;vertices[i*w*6+j*6+k].pos[1]=bottom;
		    k=4;vertices[i*w*6+j*6+k].pos[0]=right;vertices[i*w*6+j*6+k].pos[1]=top;
		    k=5;vertices[i*w*6+j*6+k].pos[0]=right;vertices[i*w*6+j*6+k].pos[1]=bottom;
		    for(int k=0;k<6;k++){
		        vertices[i*w*6+j*6+k].col[0]=col_tmp[0];
		        vertices[i*w*6+j*6+k].col[1]=col_tmp[1];
		        vertices[i*w*6+j*6+k].col[2]=col_tmp[2];
		    }

        }
	}

    GLuint vertex_buffer;
    glGenBuffers(1, &vertex_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    const GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
    glCompileShader(vertex_shader);

    const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
    glCompileShader(fragment_shader);

    const GLuint program = glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, fragment_shader);
    glLinkProgram(program);

    const GLint mvp_location = glGetUniformLocation(program, "MVP");
    const GLint vpos_location = glGetAttribLocation(program, "vPos");
    const GLint vcol_location = glGetAttribLocation(program, "vCol");

    GLuint vertex_array;
    glGenVertexArrays(1, &vertex_array);
    glBindVertexArray(vertex_array);
    glEnableVertexAttribArray(vpos_location);
    glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
                          sizeof(Vertex), (void*) offsetof(Vertex, pos));
    glEnableVertexAttribArray(vcol_location);
    glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
                          sizeof(Vertex), (void*) offsetof(Vertex, col));

    while (!glfwWindowShouldClose(window))
    {
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        const float ratio = width / (float) height;

        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);

        mat4x4 m, p, mvp;
        mat4x4_identity(m);
		// rotate axis and v
        //mat4x4_rotate_Z(m, m, (float) glfwGetTime());
        //mat4x4_rotate_X(m, m, (float) glfwGetTime());
        mat4x4_ortho(p, -ratio, ratio, -1.f,1.f, 1.f, -1.f);
        mat4x4_mul(mvp, p, m);

        glUseProgram(program);
        glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) &mvp);
        glBindVertexArray(vertex_array);
        //glDrawArrays(GL_TRIANGLES, 0, 3);
        glDrawArrays(GL_TRIANGLES, 0, w*h*6); 

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);

    glfwTerminate();
    exit(EXIT_SUCCESS);
}

//! [code]
